/*
 * Job.java
 *
 * Created on 2 de Abril de 2008, 01:24
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package Simulador.Job;

import Auxiliar.FilaEventos;
import Simulador.Event.Evento;
import Simulador.Event.InfoEventoArquivo;
import Simulador.simulador;

/**
 *
 * @author A
 */
public class Segmento {

    private FilaEventos f;

    private int id;
    private int totalLeituras;
    private int totalEscritas;
    private int memoria;
    private int idProcesso;
    private int arqId;
    
    private float totalTime;
    private float tempoExecucao;
    private float ultimaExecucao;
    
    private boolean rodando;
    private boolean requisitouIO;
    private boolean iniciado;
    

    /**Creates a new instance of Job
     * @param id
     * Id do processo
     * @param tempoTotal
     * Tempo que o processo leva para rodar.
     * @param memoria
     * Memoria que o processo utiliza quando em execucao
     * @param totalEscritas
     * Numero de pedidos de escrita que o processo vai realizar durante a execucao
     * @param totalLeituras
     * Numero de pedidos de leitura que o processo vai realizar durante a execucao
     * @param arqId
     * Id do arquivo que o processo vai acessar. 
     */
    public Segmento(int id, float tempoTotal, int memoria, int totalEscritas, int totalLeituras, int arqId) {
        f = new FilaEventos();
        this.iniciado = false;
        
        this.totalTime = tempoTotal;
        this.tempoExecucao = 0;
        this.totalLeituras = totalLeituras;
        this.totalEscritas = totalEscritas;
        this.id = id;
        this.memoria = memoria;
        this.rodando = false;
        this.requisitouIO = false;
        this.arqId = arqId;
        //Gera Eventos.
        //Evento Finaliza
        f.addItem(new Evento(Evento.FimSegmento, this, tempoTotal));

        //Eventos Leitura Arquivo
        for (int i = 0; i < totalLeituras; i++) {
            f.addItem(new Evento(Evento.RequereLeituraArquivo, this, ((tempoTotal - .01f) * (i + 1)) / (float) (totalLeituras + 1), new InfoEventoArquivo(arqId%1000, arqId - arqId%1000, false)) );
        }
        //Eventos Escrita Arquivo
        for (int i = 0; i < totalEscritas; i++) {
            f.addItem(new Evento(Evento.RequereEscritaArquivo, this, ((tempoTotal - .01f) * (i + 1)) / (float) (totalLeituras + 1), new InfoEventoArquivo(arqId%1000, arqId - arqId%1000, true)) );
        }
    }

    /**
     * coloca um evento na lista de proximos eventos do processo.
     * Só deve ser utilizado para devolver um evento retirado da lista a lista.
     * @param proxEvento
     * Evento a ser adicionado.
     */
    public void setProxEvento(Evento proxEvento) {
        f.addItem(proxEvento);
    }

    /**
     * Define a qual Job esse Processo pertence.
     * @param jobId
     * Id do Job.
     */
    public void setIdProcesso(int idProcesso) {
        this.idProcesso = idProcesso;
    }

    /**
     * @return 
     * Id do Job ao qual esse processo pertence.
     */
    public int getIdProcesso() {
        return this.idProcesso;
    }
    
    /**
     * @return
     * Retorna a quantidade de memória utilizada pelo Job.
     */
    public int getTamMemoria() {
        return memoria;
    }

    /**
     * Retorna o próximo evento se ele for ocorrer antes do fim do período de 
     * execucao.
     * @param tempoAtual
     * Momento atual da simulacao.
     * @param tempoMaximo
     * Tempo no qual o processo vai ser retirado da CPU
     * @return
     * Proximo evento.
     */
    public Evento proximoEvento(float tempoAtual, float tempoMaximo) {
        Evento e = (Evento)f.getItem();
        if( e.getMomentoDeChegada()+ tempoAtual - tempoExecucao > tempoMaximo ){
            return e;
        }else{
            f.addItem(e);
            return null;
        }
    }

    /**
     * Se o processo não havia sido começado, começa.
     * Se ja foi inicializado, continua. 
     * @param tempoAtual
     * Momento atual da simulacao
     */
    public void recomecaSegmento(float tempoAtual) {
        if (iniciado == true){
            if (rodando == false) {
                ultimaExecucao = tempoAtual;
                rodando = true;
                simulador.printEvento("Processo recomecado; tempoExecucao:"+ tempoExecucao, simulador.DEBUG_JOB, simulador.prioridadeDebug1);
            }else{
                throw new Error("Job ja estava rodando.");
            }
        }else{
            iniciado = true;
            ultimaExecucao = tempoAtual;
            rodando = true;
            simulador.printEvento("Processo comecado; tempoExecucao:"+ tempoExecucao, simulador.DEBUG_JOB,  simulador.prioridadeDebug1);
        }
    }

    /**
     * Atualiza o tempo que o processo executou e pausa o processo.
     * @param tempoAtual
     * Momento atual da simulacao.
     */
    public void pausaSegmento(float tempoAtual) {
        if (rodando == true) {
            tempoExecucao += (tempoAtual - ultimaExecucao);
            rodando = false;
            simulador.printEvento("Processo pausado; tempoExecucao:"+ tempoExecucao, simulador.DEBUG_JOB,  simulador.prioridadeDebug1);
        } else {
            throw new Error("Job ja estava pausado.");
        }
    }

    /**
     * Tratamento do Fim de IO no processo.
     */
    public void fimIO() {
        requisitouIO = false;
    }
    
    /**
     * Muda o Id do Job.
     * Só deve ser utilizado ao colocar o processo na CPU.
     * Antes de ser colocado na CPU, o processo tem um Id relativo ao Job que
     * ele pertence.
     * @param id
     * Novo Id do processo.
     */
    public void setId(int id) {
        this.id = id;
    }

    /**
     * @return
     * Id do processo.
     */
    public int getId() {
        return id;
    }
}
